package com.harmontronics.hanma.paas.paas.domain.organization.service;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.convert.Convert;
import com.baomidou.dynamic.datasource.annotation.DS;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.harmontronics.hanma.paas.paas.consts.NumberEnum;
import com.harmontronics.hanma.paas.paas.domain.organization.entity.OrgTree;
import com.harmontronics.hanma.paas.paas.domain.organization.entity.valueobject.Constants;
import com.harmontronics.hanma.paas.paas.domain.organization.entity.valueobject.HmOrgFields;
import com.harmontronics.hanma.paas.paas.domain.organization.entity.valueobject.HmUserOrgFields;
import com.harmontronics.hanma.paas.paas.domain.organization.entity.valueobject.I18nKeyEnum;
import com.harmontronics.hanma.paas.paas.domain.organization.repository.mapper.HmUserOrgMapper;
import com.harmontronics.hanma.paas.paas.domain.organization.repository.persistence.HmOrgRepository;
import com.harmontronics.hanma.paas.paas.domain.organization.entity.HmOrg;
import com.harmontronics.hanma.paas.paas.domain.organization.repository.persistence.HmUserOrgRepository;
import com.harmontronics.hanma.paas.paas.domain.organization.repository.po.HmUserOrgPO;
import com.harmontronics.hanma.paas.paas.exception.ErrorKeyException;
import com.harmontronics.hanma.paas.paas.utils.PinYinUtils;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
import java.util.function.Function;
import java.util.stream.Collectors;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.harmontronics.hanma.paas.paas.common.PageBase;

import com.harmontronics.hanma.paas.paas.domain.organization.repository.mapper.HmOrgMapper;
import com.harmontronics.hanma.paas.paas.domain.organization.repository.po.HmOrgPO;
import java.util.List;

@Service("hmOrgService")
@DS("#header.App-Unique")
public class HmOrgService {

    @Autowired
    private HmOrgRepository hmOrgRepository;

    @Autowired
    private HmOrgMapper hmOrgMapper;

    @Autowired
    private HmUserOrgService hmUserOrgService;

    @Autowired
    private HmUserOrgRepository hmUserOrgRepository;

    @Autowired
    private HmUserOrgMapper hmUserOrgMapper;


    public HmOrg findById( Long id){
            HmOrgPO po =   hmOrgRepository.getById(id);
        return BeanUtil.toBean(po,HmOrg.class);
    }


    public List<HmOrg> getAll() {
        List<HmOrgPO> allOrgs = hmOrgRepository.list(
                        new QueryWrapper<HmOrgPO>()
                                .eq(HmOrgFields.DELETED, NumberEnum.ZERO.getNum()));
        List<HmOrg> orderedList = new ArrayList<>();
        HmOrgPO org = allOrgs.stream().filter(e -> e.getParentId() == null).findFirst().get();
        org.setParentId(0L);
        orderChildren(org, allOrgs, orderedList);
        return orderedList;
    }


    public void save(HmOrg hmOrg){
            HmOrgPO orgCreate =  BeanUtil.toBean(hmOrg,HmOrgPO.class);
        // 校验值是否有空
        if (orgCreate.getName() == null) {
            throw new ErrorKeyException(I18nKeyEnum.ORG_NAME_IS_EMPTY);
        }
        if (orgCreate.getParentId() == null) {
            throw new ErrorKeyException(I18nKeyEnum.ORG_PARENT_IS_EMPTY);
        }

        // 查询当前节点同级是否有重名
        if (checkCurrentNodeSameName(orgCreate.getName(), orgCreate.getParentId())) {
            throw new ErrorKeyException(I18nKeyEnum.CURRENT_ORG_EXIST);
        }

        orgCreate.setFullPinyin(PinYinUtils.getHanziPinYin(orgCreate.getName(), true));
        orgCreate.setSimplicity(PinYinUtils.getHanziInitials(orgCreate.getName(), true));

        // 获取当前父类及其子节点数
        HmOrgPO parentOrg = currentOrgNodeWithId(orgCreate.getParentId());
        Long count = hmOrgMapper.selectMaxSerialNum(parentOrg.getId());
        count = count == null ? NumberEnum.ZERO.getNumLong() : count;

        // 组装数据
        StringBuilder parentPath = new StringBuilder();
        if (parentOrg != null) {
            if (parentOrg.getParentIds() != null) {
                parentPath.append(parentOrg.getParentIds());
            }
            parentPath
                    .append(Constants.LEFT_SQUARE_BRACKETS)
                    .append(parentOrg.getId())
                    .append(Constants.RIGHT_SQUARE_BRACKETS);
            orgCreate.setParentId(parentOrg.getId());
        }
        orgCreate.setParentIds(parentPath.toString());
        orgCreate.setSerialNum(count + NumberEnum.ONE.getNumLong());
        orgCreate.setDeleted(NumberEnum.ZERO.getNum());
        hmOrgRepository.save(orgCreate);
    }


    public void update(HmOrg hmOrg){
            HmOrgPO org =  BeanUtil.toBean(hmOrg,HmOrgPO.class);

        if (org.getDeleted() != null && org.getDeleted() == 1) {
            delete(org.getId());
            return;
        }

        // 根据id查询当前节点是否已删除
        HmOrgPO currentOrg = currentOrgNodeWithId(org.getId());

        validateField(org.getId(), org.getName(), org.getParentId());

        // 判断 当前节点是否更改父节点
        if (currentOrg.getParentId() != null && !currentOrg.getParentId()
                .equals(org.getParentId())) {
            // 取出修改后的父节点 及其 子节点总数
            HmOrgPO parentNode = currentOrgNodeWithId(org.getParentId());
            int num = currentOrgNodeTotalWithParentId(org.getParentId());
            if (parentNode.getParentIds() == null) {
                parentNode.setParentIds("");
            }
            currentOrg.setParentIds(
                    parentNode.getParentIds()
                            + Constants.LEFT_SQUARE_BRACKETS
                            + parentNode.getId()
                            + Constants.RIGHT_SQUARE_BRACKETS);
            currentOrg.setSerialNum(num + NumberEnum.ONE.getNumLong());
            currentOrg.setParentId(org.getParentId());
        }
        currentOrg.setName(org.getName());
        currentOrg.setFullPinyin(PinYinUtils.getHanziPinYin(currentOrg.getName(), true));
        currentOrg.setSimplicity(PinYinUtils.getHanziInitials(currentOrg.getName(), true));

        hmOrgMapper.updateById(currentOrg);
        //修改子部门parentids
        updateChildrenParentIds(currentOrg);
    }

    /**
     * 删除组织树节点
     */
    public void delete(Long id) {
        HmOrgPO currentOrg =
                hmOrgMapper.selectOne(
                        new QueryWrapper<HmOrgPO>()
                                .eq(HmOrgFields.DELETED, NumberEnum.ZERO.getNum())
                                .eq(HmOrgFields.ID, id));
        if (currentOrg == null) {
            throw new ErrorKeyException(I18nKeyEnum.CURRENT_NODE_NOT_EXIST_OR_HAS_BEEN_DELETED);
        }


        // 部门下没有在职员工或者子部门才可以删除。
        // 部门中还有在职员工提示：“该部门下还有子部门，无法删除”
        if (checkChildOrgWithId(id) > 0) {
            throw new ErrorKeyException(I18nKeyEnum.THERE_ARE_KID_ORG_NOT_ALLOWED_DELETE);
        }

        // 部门中还有子部门提示：“该部门下还有员工，无法删除”
        List<Long> orgIds = getChildOrgIdWithId(id);
        if (hmUserOrgService.selectUserWithOrgIds(orgIds)) {
            throw new ErrorKeyException(I18nKeyEnum.THERE_ARE_KID_USER_NOT_ALLOWED_DELETE);
        }

        // 删除当前节点
        HmOrgPO orgPO = new HmOrgPO();
        orgPO.setId(id);
        orgPO.setDeleted(NumberEnum.ONE.getNum());
        hmOrgMapper.updateById(orgPO);
        //删除用户和组织关联关系
        List<HmUserOrgPO> userOrgs = hmUserOrgRepository
                .list(new QueryWrapper<HmUserOrgPO>().eq(HmUserOrgFields.ORG_ID, id));
        for (HmUserOrgPO userOrg : userOrgs) {
            userOrg.setDeleted(NumberEnum.ONE.getNum());
            hmUserOrgRepository.updateById(userOrg);
        }

        // 移动其他节点
        moveOtherNodeWithId(currentOrg.getParentId());
    }


    public void up(Long id) {
        this.move(id, Constants.UP);

    }

    /**
     * 向下移动
     */
    public void down(Long id) {
        this.move(id, Constants.DOWN);
    }

    /**
     * 移动节点
     */
    public void move(Long id,String move) {
        // 获取当前节点并判断是否为空
        HmOrgPO currentOrg = currentOrgNodeWithId(id);

        Long moveNum =
                Constants.UP.equals(move)
                        ? currentOrg.getSerialNum() - NumberEnum.ONE.getNumLong()
                        : currentOrg.getSerialNum() + NumberEnum.ONE.getNumLong();
        currentOrg.setSerialNum(moveNum);

        // 查询当父节点下的所有子节点
        List<HmOrgPO> orgNodeList = orgNodeWithParentId(currentOrg);

        // 移动节点
        Map<Long, HmOrgPO> orgMap =
                orgNodeList.stream()
                        .collect(Collectors.toMap(HmOrgPO::getSerialNum, Function.identity()));
        HmOrgPO downOrg = orgMap.get(moveNum);
        if (Constants.UP.equals(move)) {
            downOrg.setSerialNum(moveNum + NumberEnum.ONE.getNumLong());
        } else {
            downOrg.setSerialNum(moveNum - NumberEnum.ONE.getNumLong());
        }

        List<HmOrgPO> orgList = new ArrayList<>(NumberEnum.TWO.getNum());
        orgList.add(currentOrg);
        orgList.add(downOrg);

        hmOrgRepository.updateBatchById(orgList);
    }

    /**
     * 根据父节点获取所有子节点
     */
    private List<HmOrgPO> orgNodeWithParentId(HmOrgPO currentOrg) {
        List<HmOrgPO> orgList =
                hmOrgMapper.selectList(
                        new QueryWrapper<HmOrgPO>()
                                .eq(HmOrgFields.PARENT_ID, currentOrg.getParentId())
                                .eq(HmOrgFields.DELETED, NumberEnum.ZERO.getNum())
                                .orderByAsc(HmOrgFields.SERIAL_NUM));
        if (CollectionUtils.isEmpty(orgList)) {
            throw new ErrorKeyException(I18nKeyEnum.THERE_ARE_NO_NODE_IN_CURRENT_DIR);
        }
        return orgList;
    }


    private boolean checkCurrentNodeSameName(String name, Long parentId) {
        HmOrgPO sameNameOrg =
                hmOrgMapper.selectOne(
                        new QueryWrapper<HmOrgPO>()
                                .eq(HmOrgFields.NAME, name)
                                .eq(HmOrgFields.PARENT_ID, parentId)
                                .eq(HmOrgFields.DELETED, NumberEnum.ZERO.getNum()));
        return sameNameOrg != null;
    }

    /**
     * 根据id获取当前节点
     */
    private HmOrgPO currentOrgNodeWithId(Long id) {
        HmOrgPO currentOrg =
                hmOrgMapper.selectOne(
                        new QueryWrapper<HmOrgPO>()
                                .eq(HmOrgFields.ID, id)
                                .eq(HmOrgFields.DELETED, NumberEnum.ZERO.getNum()));
        if (currentOrg == null) {
            throw new ErrorKeyException(I18nKeyEnum.CURRENT_NODE_NOT_EXIST);
        }
        return currentOrg;
    }

    private int checkChildOrgWithId(Long id) {
        return hmOrgMapper.selectCount(
                new QueryWrapper<HmOrgPO>()
                        .eq(HmOrgFields.DELETED, NumberEnum.ZERO.getNum())
                        .eq(HmOrgFields.PARENT_ID, id));
    }

    /**
     * 获取当前节点的子节点信息
     */
    private List<Long> getChildOrgIdWithId(Long id) {
        List<HmOrgPO> orgList =
                hmOrgMapper.selectList(
                        new QueryWrapper<HmOrgPO>()
                                .eq(HmOrgFields.DELETED, NumberEnum.ZERO.getNum())
                                .eq(HmOrgFields.PARENT_ID, id)
                                .orderByAsc(HmOrgFields.SERIAL_NUM));
        List<Long> orgIdList = orgList.stream().map(HmOrgPO::getId).collect(Collectors.toList());
        orgIdList.add(id);
        return orgIdList;
    }


    public void validateField(Long id, String value, Long parentId) {
        QueryWrapper<HmOrgPO> wrapper = new QueryWrapper<>();
        wrapper.eq(HmOrgFields.NAME, value);
        wrapper
                .eq(HmOrgFields.PARENT_ID, parentId)
                .eq(HmOrgFields.DELETED, NumberEnum.ZERO.getNum());

        // 修改
        if (id != null) {
            wrapper.ne(HmOrgFields.ID, id);
        }

        validateFieldImpl(HmOrgFields.NAME, wrapper);
    }


    private void validateFieldImpl(String key, QueryWrapper<HmOrgPO> wrapper) {
        HmOrgPO org = hmOrgMapper.selectOne(wrapper);

        if (Optional.ofNullable(org).isPresent()) {
            throw new ErrorKeyException(I18nKeyEnum.CURRENT_ORG_EXIST);
        }
    }

    /**
     * 根据父节点获取所有子节点个数
     */
    private int currentOrgNodeTotalWithParentId(Long parentId) {
        return hmOrgMapper.selectCount(
                new QueryWrapper<HmOrgPO>()
                        .eq(HmOrgFields.PARENT_ID, parentId)
                        .eq(HmOrgFields.DELETED, NumberEnum.ZERO.getNum()));
    }

    private void updateChildrenParentIds(HmOrgPO currentOrg) {
        QueryWrapper<HmOrgPO> wrapper = new QueryWrapper<HmOrgPO>()
                .eq(HmOrgFields.PARENT_ID, currentOrg.getId());

        List<HmOrgPO> orgs = hmOrgMapper.selectList(wrapper);
        if (currentOrg.getParentIds() == null) {
            currentOrg.setParentIds("");
        }
        for (HmOrgPO org : orgs) {
            org.setParentIds(
                    currentOrg.getParentIds()
                            + Constants.LEFT_SQUARE_BRACKETS
                            + currentOrg.getId()
                            + Constants.RIGHT_SQUARE_BRACKETS);
            hmOrgMapper.updateById(org);
            updateChildrenParentIds(org);
        }

    }

    private void moveOtherNodeWithId(Long parentId) {
        List<Long> orgIds = getChildOrgIdWithId(parentId);
        orgIds.remove(parentId);
        if (CollectionUtils.isNotEmpty(orgIds)) {
            long serialNum = NumberEnum.ONE.getNumLong();
            for (Long orgId : orgIds) {
                HmOrgPO orgPO = new HmOrgPO();
                orgPO.setId(orgId);
                orgPO.setSerialNum(serialNum++);
                hmOrgMapper.updateById(orgPO);
            }
        }
    }

    private void orderChildren(HmOrgPO org, List<HmOrgPO> allOrgs, List<HmOrg> orderedList) {
        orderedList.add(BeanUtil.toBean(org, HmOrg.class));
        List<HmOrgPO> children =
                allOrgs.stream()
                        .filter(e -> org.getId().equals(e.getParentId()))
                        .sorted((o1, o2) -> (int) (o1.getSerialNum() - o2.getSerialNum()))
                        .collect(Collectors.toList());
        for (HmOrgPO o : children) {
            orderChildren(o, allOrgs, orderedList);
        }
    }


    public List<Long> selectChildrenIdWithId(Long orgId, boolean includeDeleted) {
        HmOrgPO currentOrg = hmOrgMapper.selectById(orgId);
        String parentIds = currentOrg.getParentIds() == null ? "" : currentOrg.getParentIds();
        QueryWrapper<HmOrgPO> wrapper = new QueryWrapper<HmOrgPO>()
                .likeRight(
                        HmOrgFields.PARENT_IDS,
                        parentIds
                                + Constants.LEFT_SQUARE_BRACKETS
                                + orgId
                                + Constants.RIGHT_SQUARE_BRACKETS)
                .orderByAsc(HmOrgFields.SERIAL_NUM);
        if (!includeDeleted) {
            wrapper.eq(HmOrgFields.DELETED, NumberEnum.ZERO.getNum());
        }
        List<HmOrgPO> orgList =
                hmOrgMapper.selectList(
                        wrapper);
        orgList.add(currentOrg);
        return orgList.stream().map(HmOrgPO::getId).collect(Collectors.toList());
    }


    public List<Long> selectChildrenIdWithId(Long id) {

        return selectChildrenIdWithId(id, false);
    }

    public Long selectMaxSerialNum(Long orgId) {
        Long count = hmOrgMapper.selectMaxSerialNum(orgId);
        return count == null ? NumberEnum.ZERO.getNumLong() : count;
    }


    public Map<String, Long> selectOrgTreeWithOrgId(Long orgId) {
        OrgTree orgTree = hmOrgMapper.selectOrgTreeWithOrgId(orgId);
        Map<String, Long> resultMap = new HashMap<>();
        // 当前父节点不要，从子节点开始处理
        //    resultMap.put(orgTree.getName(), orgTree.getId());
        dealArrOrg(resultMap, null, orgTree.getChildren());
        return resultMap;
    }

    private void dealArrOrg(Map<String, Long> resultMap, String name,
            List<OrgTree> orgTreeList) {
        if (CollectionUtils.isNotEmpty(orgTreeList)) {
            for (OrgTree orgTreeDto : orgTreeList) {
                String key = "";
                if (name == null) {
                    name = "";
                }
                key = name + orgTreeDto.getName();
                if (!resultMap.containsKey(key)) {
                    resultMap.put(key, orgTreeDto.getId());
                }
                dealArrOrg(resultMap, key + "/", orgTreeDto.getChildren());
            }
        }
    }


    public List<Long> selectOrgParentIdWithUserId(Long userId) {
        List<Long> parentIds = new ArrayList<>();
        List<HmOrgPO> orgList = hmOrgMapper.selectOrgWithUserId(userId);
        for (HmOrgPO org : orgList) {
            parentIds.addAll(parseParentIdsWithOrg(org));
        }
        return parentIds;
    }

    private List<Long> parseParentIdsWithOrg(HmOrgPO org) {
        List<Long> parentIdList = new ArrayList<>();
        if (org.getParentIds() != null) {
            String parentIdStr = org.getParentIds().substring(1, org.getParentIds().length() - 1);
            parentIdList =
                    Arrays.stream(parentIdStr.split(Constants.PARENTID))
                            .map(Long::parseLong)
                            .collect(Collectors.toList());
        }
        parentIdList.add(org.getId());
        return parentIdList;
    }

    public List<Long> userBelongTo(List<Long> orgIds, Long userId) {
        if(orgIds.isEmpty()){
            return new ArrayList<>();
        }
        List<HmOrgPO> orgs = hmUserOrgMapper.selectOrgByUserId(userId);
        List<Long> resultOrgIds = new ArrayList<>();
        for(Long orgId:orgIds){
            for(HmOrgPO org:orgs){
                if(orgId.longValue() == org.getId().longValue()){
                    resultOrgIds.add(orgId);
                    continue;
                }
                if(org.getParentIds()!=null&&org.getParentIds().contains("["+ orgId +"]")){
                    resultOrgIds.add(orgId);
                }

            }
        }

        return resultOrgIds;
    }

    public HmOrg getRootOrg(){
        QueryWrapper<HmOrgPO> queryWrapper = new QueryWrapper<>();
        queryWrapper.isNull(HmOrgFields.PARENT_ID);
        HmOrgPO hmOrgPO = hmOrgRepository.getOne(queryWrapper);
        return BeanUtil.toBean(hmOrgPO,HmOrg.class);
    }

}